"""
The MIT License (MIT)
Copyright © 2021 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-video-stream
"""
import socket
from utime import sleep
from config import Commands
import framebuf
import _thread
import gc
from micropython import alloc_emergency_exception_buf

alloc_emergency_exception_buf(100)


class Handler(object):
	def __init__(self, client, server_addr, oled):
		self.__client = client
		self.__server_addr = server_addr
		self.__oled = oled
		self.__buffer_list = []
		self.__ready_to_receive = True
		self.__lock = _thread.allocate_lock()

		self.buffer_size = 1200 # 缓冲区大小
		self.min_frames = 10 # 小于 min 值则向服务器请求数据
		self.max_frames = 30 # 大于 max 值则停止请求数据

	def __fill_buffer(self, buffer):
		if isinstance(buffer, (bytes, memoryview)):
			buffer = framebuf.FrameBuffer(bytearray(buffer), 128, 64, framebuf.MONO_HMSB)
		else:
			buffer = None

		return buffer

	def start(self):
		self.__client.sendto(Commands.REQUEST_ONE_FRAMES, self.__server_addr)

		_thread.start_new_thread(self.__receive_buffer_thread, ())
		sleep(0.5)
		_thread.start_new_thread(self.__show_buffer_thread, ())

	def __show_buffer_thread(self):
		print('### start show buffer thread')
		while True:
			if len(self.__buffer_list):
				with self.__lock:
					fb_buffer = self.__fill_buffer(self.__buffer_list.pop(0))

				if fb_buffer:
					self.__oled.blit(fb_buffer, 0, 0)
					self.__oled.show()

				gc.collect()

				if len(self.__buffer_list) <= self.min_frames:
					self.__ready_to_receive = True

			sleep(0.0002)

	def __receive_buffer_thread(self):
		print('### start receive buffer thread')
		recv = self.__client.recvfrom
		sendto = self.__client.sendto

		while True:
			if not self.__ready_to_receive:
				continue

			if len(self.__buffer_list) < self.max_frames:
				sendto(Commands.REQUEST_ONE_FRAMES, self.__server_addr)
			else:
				self.__ready_to_receive = False

			try:
				server_data, server_addr = recv(self.buffer_size)

				if not server_data or server_addr != self.__server_addr:
					continue

				if server_data.startswith(Commands.SENDING_ONE_FRAME):
					server_data = memoryview(server_data.split(Commands.SENDING_ONE_FRAME)[1])
					self.__buffer_list.append(server_data)
					gc.collect()
			except OSError as ose:
				if str(ose) == '[Errno 11] EAGAIN':
					continue
				else:
					print(ose)
			except Exception as e:
				print(e)

			sleep(0.0002)


class Client(object):
	def __init__(self, oled):
		assert oled is not None

		self.__client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.__client.setblocking(False)
		self.__oled = oled

	def start(self, host:str, port:int=26688):
		assert host is not None

		handler = Handler(self.__client, (host, port), self.__oled)
		handler.max_frames = 30
		handler.min_frames = 10
		handler.buffer_size = int((self.__oled.width * self.__oled.height) / 8 + 100)
		handler.start()


# for testing
if __name__ == '__main__':
	import framebuf
	from machine import I2C, Pin
	from drivers.ssd1306 import SSD1306_I2C

	buffer = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00@\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\xf3\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\xff\xff\xe8\x01\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x01\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x01\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x01\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x01\x00\x00\xe7\xf3\xff\xff\x00\x00\xfe\x00\x00\x00\x00 \x00\x01\x00\x00\xcf\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00 \x00\x01\x00\x00\x07\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00`\x00\x00\x00\x00o\xf7\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00@\x00\x00\x00\x00\x07\xf8\xff\xff\x00\x00\xfe\x00\x00\x00\x00@\x00\x00\x00\x00\x07\xf8\xff\xff\x00\x00\xfe\x00\x00\x00\x00@\x00\x00\x00\x00\x07\xf8\xff\xff\x00\x00\xfe\x00\x00\x00\x00\xe0@\x00\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\xe0\xc1\x00\x00\x00\xe7\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\xe0\xc3\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\xc0s\x00\x00\x00\x07\xf1\xff\xff\x00\x00\xfe\x00\x00\x00\x00\xc0a\x00\x00\x00\x0f\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x80\x01\x00\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x80\x01\x00\x00\x00\x07\xf0\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x80\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x01\x00\x00\x00\x07\xf1\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00G\xf8\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xf3\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xfe\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x18?\xfb\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00<\x07\xfa\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00<\x07\xfc\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf8\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xf0\xff\xff\x00\x00\xfe\xff\xffX\x00\x00\x00\x00\x00\x00\x07\xf4\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\xf3\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\xf0\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfd\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\xf0\xff\xff\x00\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\xf0\xff\xff\x02I\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00  \x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
	fb_buffer = framebuf.FrameBuffer(bytearray(buffer), 128, 64, framebuf.MONO_HMSB)
	i2c = I2C(0, scl=Pin(18), sda=Pin(19))
	slave_list = i2c.scan()

	if slave_list:
		print('slave id: {}'.format(slave_list[0]))
		oled = SSD1306_I2C(128, 64, i2c)

		oled.blit(fb_buffer, 0, 0)
		oled.show()
